package net.cyue.easyconfiguration.node.definition;

import net.cyue.easyconfiguration.node.NodeType;
import net.cyue.easyconfiguration.node.api.INodeTypeConverter;
import net.cyue.easyconfiguration.node.util.NodePathUtil;

import java.util.Arrays;

public abstract class AbstractNodeDefinition {
    protected boolean ignore = false;
    protected boolean multiNode = false;
    protected AbstractNodeDefinition parent;
    protected String name;
    protected String[] paths;
    protected NodeType type;
    protected Class<?> javaType;
    protected boolean forceConvert;
    protected INodeTypeConverter typeConverter;

    public AbstractNodeDefinition(
        AbstractNodeDefinition parent,
        NodeType type,
        String name,
        String... paths
    ) {
        this(parent, type, null, name, paths);
    }
    public AbstractNodeDefinition(
        AbstractNodeDefinition parent,
        NodeType type,
        INodeTypeConverter typeConverter,
        String name,
        String... paths
    ) {
        this.parent = parent;
        this.type = type;
        this.name = name;
        this.setPaths(paths == null ? new String[]{name} : paths);
        this.forceConvert = true;
        this.typeConverter = typeConverter;
    }

    @Override
    public int hashCode() {
        return (this.name + "@" + Arrays.toString(this.getFullPaths())).hashCode();
    }

    public void setMultiNode(boolean multiNode) {
        this.multiNode = multiNode;
        // 存在通配符的，则强制多节点
        if (NodePathUtil.hasWildcardPath(this.paths)) {
            this.multiNode = true;
        }
    }
    public void setParent(AbstractNodeDefinition parent) {
        this.parent = parent;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setPaths(String... paths) {
        this.paths = paths;
        // 存在通配符，则为多节点
        if (NodePathUtil.hasWildcardPath(this.paths)) {
            this.multiNode = true;
        }
    }
    public void setType(NodeType type) {
        this.type = type;
    }
    public void setJavaType(Class<?> javaType) {
        this.javaType = javaType;
    }
    public void setNodeType(NodeType type) {
        this.type = type;
    }
    public void setForceConvert(boolean forceConvert) {
        this.forceConvert = forceConvert;
    }
    public void setTypeConverter(INodeTypeConverter typeConverter) {
        this.typeConverter = typeConverter;
    }

    public boolean isIgnore() {
        return this.ignore;
    }
    public boolean isMultiNode() {
        return this.multiNode;
    }
    public AbstractNodeDefinition getParent() {
        return this.parent;
    }
    public NodeType getType() {
        return this.type;
    }
    public Class<?> getJavaType() {
        return this.javaType;
    }
    public String getName() {
        return this.name;
    }
    public String getPath() {
        return this.paths[0];
    }
    public String[] getPaths() {
        return this.paths;
    }
    public String getFullPath() {
        if (this.parent == null) {
            return this.getPath();
        }
        return this.parent.getFullPath() + "." + this.getPath();
    }
    public String[] getFullPaths() {
        if (this.parent == null) {
            return this.paths;
        }
        String[] parentFullPaths = this.parent.getFullPaths();
        String[] fullPaths = new String[parentFullPaths.length * this.paths.length];
        for (int i = 0; i < parentFullPaths.length; i++) {
            for (int j = 0; j < this.paths.length; j++) {
                fullPaths[i * this.paths.length + j] = parentFullPaths[i] + "." + this.paths[j];
            }
        }
        return fullPaths;
    }

    public boolean isForceConvert() {
        return this.forceConvert;
    }
    public INodeTypeConverter getTypeConverter() {
        return this.typeConverter;
    }

    public Object convert(Object value) {
        if (this.typeConverter == null) {
            return value;
        }
        return this.typeConverter.convert(value, this.paths);
    }
}
